import __builtin__
import networking.ganet as ganet
import networking.ganet.network.message as message
from direct.gui.DirectGui import *
from client.gamestates.staterunningsession import Role

#IP = "sick.webhop.me"
IP = '127.0.0.1'


class User(object):
    def __init__(self, id = 0, name = 0):
        self.name = name
        self.id = id

    def set(self, id, name):
        self.name = name
        self.id = id


class NetworkManager(object):
    ###############################################################################################################
    ###############################################################################################################
    ########################                         C O M M O N                           ########################
    ###############################################################################################################
    ###############################################################################################################

    def __init__(self):
        self.nw = 0
        self.server_peer = 0
        self.clients_online = 0
        self.my_user = User()

    def init_network(self):
        self.nw = ganet.network.Network()
        self.my_listener = NetListener(self)
        self.nw.add_listener(self.my_listener)

        self.connect(self.nw)
        self.nw.startup()

        __builtin__.base.guimanager.toggle_element_active("BtnMulti", "Connecting...", False)

    def connect(self, nw):
        addr = (IP, 54321)
        print 'sending connect to %s:%d' % addr
        nw.connect(addr)

    def close_network(self):
        if self.nw != 0:
            self.nw.shutdown()
            self.nw.remove_listener(self.my_listener)
            self.nw = 0
            __builtin__.base.guimanager.toggle_element_active("BtnMulti", "Multiplayer", True)

    def update(self, dt):
        if self.nw != 0:
            self.nw.update(dt)

    def prep_msg(self, msg_type):
        encoder = message.MessageEncoder()
        encoder.reset()
        encoder.write_string(msg_type)
        return encoder






    ###############################################################################################################
    ###############################################################################################################
    ########################                          L O B B Y                            ########################
    ###############################################################################################################
    ###############################################################################################################

    def enter_lobby(self, dec):
        self.my_user.id = dec.read_string()
        self.send_changed_nick()

    def set_user_online(self, dec):
        self.clients_online = dec.read_int()
        __builtin__.base.guimanager.update_user_online()

    def client_left(self, dec):
        self.clients_online -= 1
        __builtin__.base.guimanager.update_user_online()

    def send_chat_msg(self, msg):
        encoder = self.prep_msg("chat_msg")
        encoder.write_string(msg)
        msg = encoder.get_message()

        self.server_peer.send_reliable_sequenced(msg)

    def got_chat_msg(self, dec):
        __builtin__.base.guimanager.set_chat_text(dec.read_string())

    def send_changed_nick(self):
        encoder = self.prep_msg("changed_nick")
        encoder.write_string(self.my_user.id)
        encoder.write_string(self.my_user.name)
        msg = encoder.get_message()

        self.server_peer.send_reliable_sequenced(msg)

    def request_user_online(self):
        encoder = self.prep_msg("number_user_online")
        msg = encoder.get_message()
        self.server_peer.send_reliable_sequenced(msg)

    def send_request_gamelist(self):
        encoder = self.prep_msg("request_gamelist")
        self.server_peer.send_reliable_sequenced(encoder.get_message())

    def requested_gamelist(self, dec):
        if "SessionList" in __builtin__.base.guimanager.curGUI:
            __builtin__.base.guimanager.clear_session_list()

            numSessions = dec.read_int()
            for i in range(0, numSessions):
                ses = dec.read_int()
                creator = dec.read_string()
                btn = DirectButton(text=str(creator) + "'s Game", pos=(0, 0, 0.1), scale=0.07, command=self.send_join_session, extraArgs=[ses])
                __builtin__.base.guimanager.curGUI["SessionList"].addItem(btn)





    ###############################################################################################################
    ###############################################################################################################
    ########################                     C R E A T E   G A M E                     ########################
    ###############################################################################################################
    ###############################################################################################################

    def send_create_session(self):
        encoder = self.prep_msg("request_new_session")
        msg = encoder.get_message()

        self.server_peer.send_reliable_sequenced(msg)

    def send_join_session(self, ses_id):
        encoder = self.prep_msg("request_join_session")
        encoder.write_int(ses_id)
        msg = encoder.get_message()

        self.server_peer.send_reliable_sequenced(msg)

    def session_created(self, peer, dec):

        __builtin__.base.gamestatemanager.getState("CreateGame").ses_id = dec.read_int()
        __builtin__.base.gamestatemanager.getState("CreateGame").is_creator = True
        __builtin__.base.gamestatemanager.getState("CreateGame").attacker = User(dec.read_int(), dec.read_string())

        __builtin__.base.gamestatemanager.demand("CreateGame")
        __builtin__.base.guimanager.update_creategame()
        __builtin__.base.guimanager.curGUI["BtnStart"].hide()

    def session_joined(self, dec):
        __builtin__.base.gamestatemanager.demand("CreateGame")
        __builtin__.base.gamestatemanager.getState("CreateGame").ses_id = dec.read_int()
        __builtin__.base.guimanager.curGUI["BtnStart"].hide()
        __builtin__.base.guimanager.curGUI["BtnToggleRole"].hide()

    def send_shutdown_session(self):
        encoder = self.prep_msg("shutdown_session")
        encoder.write_int(__builtin__.base.gamestatemanager.getState("CreateGame").ses_id)
        msg = encoder.get_message()

        self.server_peer.send_reliable_sequenced(msg)

    def send_session_left(self):
        encoder = self.prep_msg("session_left")
        encoder.write_int(__builtin__.base.gamestatemanager.getState("CreateGame").ses_id)
        msg = encoder.get_message()

        self.server_peer.send_reliable_sequenced(msg)

    def send_toggle_roles(self):
        encoder = self.prep_msg("request_toggle_roles")
        encoder.write_int(__builtin__.base.gamestatemanager.getState("CreateGame").ses_id)
        msg = encoder.get_message()

        self.server_peer.send_reliable_sequenced(msg)

    def update_session_roles(self, dec):
        __builtin__.base.gamestatemanager.getState("CreateGame").attacker = User(dec.read_int(), dec.read_string())
        __builtin__.base.gamestatemanager.getState("CreateGame").defender = User(dec.read_int(), dec.read_string())

        if __builtin__.base.gamestatemanager.getState("CreateGame").attacker.id == 0:
            __builtin__.base.gamestatemanager.getState("CreateGame").attacker = 0
        elif str(__builtin__.base.gamestatemanager.getState("CreateGame").attacker.id) == str(self.my_user.id):
            __builtin__.base.gamestatemanager.getState("RunningSession").role = Role.ATTACKER

        if __builtin__.base.gamestatemanager.getState("CreateGame").defender.id == 0:
            __builtin__.base.gamestatemanager.getState("CreateGame").defender = 0
        elif str(__builtin__.base.gamestatemanager.getState("CreateGame").defender.id) == str(self.my_user.id):
                __builtin__.base.gamestatemanager.getState("RunningSession").role = Role.DEFENDER

        __builtin__.base.guimanager.update_creategame()

    def send_session_start(self):
        encoder = self.prep_msg("request_session_start")
        encoder.write_int(__builtin__.base.gamestatemanager.getState("CreateGame").ses_id)
        msg = encoder.get_message()

        self.server_peer.send_reliable_sequenced(msg)

    def session_started(self, dec):
        role = dec.read_int()

        if role == 0:
            __builtin__.base.gamestatemanager.getState("RunningSession").role = Role.ATTACKER
        else:
            __builtin__.base.gamestatemanager.getState("RunningSession").role = Role.DEFENDER

        __builtin__.base.gamestatemanager.demand("RunningSession")
        __builtin__.base.gamestatemanager.getState("RunningSession").started = True

    def session_closed(self):
        __builtin__.base.gamestatemanager.getState("CreateGame").reset_session()
        __builtin__.base.gamestatemanager.demand("Lobby")


class NetListener(ganet.network.NetworkListener):
    def __init__(self, client):
        self.client = client

    def on_new_connection(self, peer):
        print 'LISTENER: new connection from %s:%d' % peer.addr

    def on_peer_lost(self, peer):
        print 'LISTENER: peer lost %s:%d' % peer.addr
        #if peer is self.client.server_peer and str(__builtin__.base.gamestatemanager.curState.name) != "MainMenu":
        #    __builtin__.base.gamestatemanager.demand("MainMenu")

    def on_peer_disconnected(self, peer):
        print 'LISTENER: peer disconnected %s:%d' % peer.addr
        #if peer is self.client.server_peer and str(__builtin__.base.gamestatemanager.curState.name) != "MainMenu":
        #    __builtin__.base.gamestatemanager.demand("MainMenu")

    def on_connection_accepted(self, peer):
        print 'LISTENER: peer accepted connection %s:%d' % peer.addr
        self.client.server_peer = peer
        self.client.my_user.name = __builtin__.base.guimanager.curGUI["PlayerName"].get()
        __builtin__.base.gamestatemanager.demand("Lobby")

    def on_connection_refused(self, peer):
        print 'LISTENER: peer refused %s:%d' % peer.addr
        __builtin__.base.guimanager.toggle_element_active("BtnMulti", "Multiplayer", True)

    def on_message(self, peer, msg):
        print 'LISTENER: message from %s:%d: %s' % (peer.addr[0], peer.addr[1], msg)
        dec = message.MessageDecoder()
        dec.reset(msg)
        type = dec.read_string()

        if type == "enter_lobby":
            self.client.enter_lobby(dec)
        elif type == "client_left":
            self.client.client_left(dec)
        elif type == "changed_nick":
            self.client.changed_nick(dec)
        elif type == "chat_msg":
            self.client.got_chat_msg(dec)
        elif type == "requested_gamelist":
            self.client.requested_gamelist(dec)
        elif type == "user_online":
            self.client.set_user_online(dec)
        elif type == "session_created":
            self.client.session_created(peer, dec)
        elif type == "session_joined":
            self.client.session_joined(dec)
        elif type == "update_session_roles":
            self.client.update_session_roles(dec)
        elif type == "session_started":
            self.client.session_started(dec)
        elif type == "session_closed":
            self.client.session_closed()
        if not __builtin__.base.gamestatemanager.curState.name == "Game":
            return
        if type == "settings":
            __builtin__.base.gamestatemanager.getState("RunningSession").update_settings(dec)
        elif type == "place_unit":
            __builtin__.base.gamestatemanager.curState.place_unit(dec)
        elif type == "place_warpzone":
            __builtin__.base.gamestatemanager.curState.place_warpzone(dec)
        elif type == "place_tower":
            __builtin__.base.gamestatemanager.curState.place_tower(dec)
        elif type == "shoot_projectile":
            __builtin__.base.gamestatemanager.curState.shoot_projectile(dec)
        elif type == "upgrade":
            __builtin__.base.gamestatemanager.curState.upgrade(dec)
        elif type == "destroy_unit":
            __builtin__.base.gamestatemanager.curState.destroy_unit(dec)
        elif type == "destroy_tower":
            __builtin__.base.gamestatemanager.curState.destroy_tower(dec)
        elif type == "remove_projectile":
            __builtin__.base.gamestatemanager.curState.remove_projectile(dec)
        elif type == "update_position":
            __builtin__.base.gamestatemanager.curState.update_position(dec)
        elif type == "update_projectileposition":
            __builtin__.base.gamestatemanager.curState.update_projectiles(dec)
        elif type == "phase_fight":
            __builtin__.base.gamestatemanager.curState.phase_fight()
        elif type == "phase_prepare":
            __builtin__.base.gamestatemanager.curState.phase_prepare()
        elif type == "grace_period":
            __builtin__.base.gamestatemanager.curState.grace_period()
        elif type == "select":
            __builtin__.base.gamestatemanager.curState.select(dec)
        elif type == "update_units":
            __builtin__.base.gamestatemanager.curState.update_units(dec)
        elif type == "update_towers":
            __builtin__.base.gamestatemanager.curState.update_towers(dec)
        elif type == "update_money":
            __builtin__.base.gamestatemanager.curState.update_money(dec)
        elif type == "update_lifes":
            __builtin__.base.gamestatemanager.curState.update_lifes(dec)
        elif type == "game_over":
            __builtin__.base.gamestatemanager.curState.game_over(dec)
        elif type == "update_unitdestination":
            __builtin__.base.gamestatemanager.curState.update_unitdestination(dec)

    def on_error(self, error_num):
        print 'LISTENER: error: %d' % error_num
